use crate::structures::list_node::ListNode;

#[allow(dead_code)]
struct Solution;

impl ListNode {
    fn new_with_next(val: i32, next: Option<Box<ListNode>>) -> Self {
        Self { val, next }
    }
}

impl Solution {
    pub fn remove_elements(head: Option<Box<ListNode>>, val: i32) -> Option<Box<ListNode>> {
        let mut dummy_head = ListNode::new_with_next(0, head);
        let mut prev_node = &mut dummy_head;

        while let Some(current_node) = &mut prev_node.next {
            if current_node.val == val {
                prev_node.next = current_node.next.take();
            } else {
                prev_node = prev_node.next.as_mut().unwrap();
            }
        }

        dummy_head.next
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::structures::list_node::ListNode;

    #[test]
    fn test_remove_elements() {
        // Case 1: Remove multiple elements from the middle and end
        let head1 = ListNode::from_slice(&[1, 2, 6, 3, 4, 5, 6]);
        let val1 = 6;
        let expected1 = ListNode::from_slice(&[1, 2, 3, 4, 5]);
        assert_eq!(Solution::remove_elements(head1, val1), expected1);

        // Case 2: The input list is empty
        let head2 = ListNode::from_slice(&[]);
        let val2 = 1;
        let expected2 = ListNode::from_slice(&[]);
        assert_eq!(Solution::remove_elements(head2, val2), expected2);

        // Case 3: All elements in the list should be removed
        let head3 = ListNode::from_slice(&[7, 7, 7, 7]);
        let val3 = 7;
        let expected3 = ListNode::from_slice(&[]);
        assert_eq!(Solution::remove_elements(head3, val3), expected3);
    }
}
